/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package agents;

import jade.core.AID;
import jade.core.Agent;
import jade.core.behaviours.Behaviour;
import jade.core.behaviours.OneShotBehaviour;
import jade.core.behaviours.SequentialBehaviour;
import jade.core.behaviours.ThreadedBehaviourFactory;
import jade.domain.DFService;
import jade.domain.FIPAAgentManagement.DFAgentDescription;
import jade.domain.FIPAAgentManagement.ServiceDescription;
import jade.domain.FIPAException;
import jade.lang.acl.ACLMessage;
import jade.lang.acl.MessageTemplate;
import jade.lang.acl.UnreadableException;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;
import model.Artifact;
import model.MuseumArtifacts;
import model.User;
import view.ProfilerGUI;
import view.SMListModel;

/**
 *
 * @author CUNEYT
 *
 * This class represents the Profiler agent which is responsible for maintaining a
 * User profile and preparing virtual tours to the user according to User's interests.
 * It is responsible for performing the request made by the GUI.
 *
 */
public class ProfilerAgent extends Agent {

    private ProfilerGUI myGui;
    private User user;

    @Override
    protected void setup() {
        myGui = new ProfilerGUI(this);
        myGui.setVisible(true);
        user = myGui.createUser();
    }

    /*
     * This method is invoked by the GUI whenever the user wants to search for a
     * specific Artifact in a museum or a virtual tour. It is performed in a
     * separate thread in order not to block the GUI.
     */
    public void search(AID destination, String criteria, String searchBy) {
        ThreadedBehaviourFactory tbf = new ThreadedBehaviourFactory();
        addBehaviour(tbf.wrap(new SearchBehaviour(destination, criteria, searchBy)));
    }

    /*
     * This method is invoked by the GUI in order to search/update all of the
     * available services for use. It has a SequentialBehaviour which searches
     * for the museums/galleries first and tour guides second.
     */
    public void update() {
        SequentialBehaviour sb = new SequentialBehaviour();
        sb.addSubBehaviour(new SearchServiceBehaviour("museum/gallery"));
        sb.addSubBehaviour(new SearchServiceBehaviour("tour-guide"));
        addBehaviour(sb);
    }


    /*
     * This private class extends OneShotBehaviour and is responsible for searching
     * for services in the DF with the specified service type. The result is reflected
     * to the GUI.
     */

    private class SearchServiceBehaviour extends OneShotBehaviour {

        private String serviceType;

        public SearchServiceBehaviour(String serviceType) {
            this.serviceType = serviceType;
        }

        @Override
        public void action() {
            try {
                DFAgentDescription template = new DFAgentDescription();
                ServiceDescription sdm = new ServiceDescription();
                sdm.setType(serviceType);
                template.addServices(sdm);
                DFAgentDescription[] result = null;
                result = DFService.search(myAgent, template);
                for (int i = 0; i < result.length; i++) {
                    if (!myGui.getServices().contains(result[i].getName())) {
                        myGui.getServices().add(result[i].getName());
                    }
                }
            } catch (FIPAException ex) {
                Logger.getLogger(ProfilerGUI.class.getName()).log(Level.SEVERE, null, ex);
            }
            myGui.getServiceList().setModel(new SMListModel(myGui.getServices()));
        }
    }

    /*
     * This private class is responsible for performing the search operation according
     * to the specified parameters and criterias supplied from the GUI. The result of the
     * search operation is updated in the GUI, if there is any.
     */

    private class SearchBehaviour extends Behaviour {

        private AID destination;
        private String searchBy;
        private String criteria;
        private int step = 0;

        public SearchBehaviour(AID dest, String cri, String sBy) {
            this.destination = dest;
            this.searchBy = sBy;
            this.criteria = cri;
        }

        @Override
        public void action() {
            switch (step) {
                case 0:

                    ACLMessage msg = null;

                    if (searchBy == null) {
                        msg = new ACLMessage(ACLMessage.REQUEST);
                        msg.setContent(criteria);
                    } else {
                        msg = new ACLMessage(ACLMessage.CFP);
                        msg.setContent(searchBy + "," + criteria);
                    }
                    msg.addReceiver(destination);
                    myAgent.send(msg);
                    step = 1;
                    break;
                case 1:
                    MessageTemplate mt = null;
                    String result = "";
                    if (searchBy == null) {
                        mt = MessageTemplate.MatchPerformative(ACLMessage.INFORM);
                    } else {
                        mt = MessageTemplate.MatchPerformative(ACLMessage.PROPOSE);
                    }
                    ACLMessage reply = myAgent.receive(mt);

                    if (reply != null) {
                        if (searchBy == null) {
                            try {
                                Artifact art = (Artifact) reply.getContentObject();
                                if (art != null) {
                                    result = art.toPrintable();
                                    user.visited(art);
                                }

                            } catch (UnreadableException ex) {
                                Logger.getLogger(ProfilerAgent.class.getName()).log(Level.SEVERE, null, ex);
                            }
                        } else {
                            try {
                                ArrayList<MuseumArtifacts> art = (ArrayList<MuseumArtifacts>) reply.getContentObject();
                                if (art.size() > 0) {
                                    for (int i = 0; i < art.size(); i++) {
                                        MuseumArtifacts museumArtifacts = art.get(i);
                                        if (!museumArtifacts.getArtifacts().isEmpty()) {
                                            result += museumArtifacts.getArtifacts() + " @ " + museumArtifacts.getMuseum().getLocalName() + "\n";
                                        }
                                    }
                                } else {
                                    result = reply.getContent();
                                }
                            } catch (UnreadableException ex) {
                                Logger.getLogger(ProfilerAgent.class.getName()).log(Level.SEVERE, null, ex);
                            }
                        }
                        myGui.setResult(result);
                        step = 2;
                    } else {
                        block();
                    }
                    break;
            }
        }

        @Override
        public boolean done() {
            return step == 2;
        }
    }
}
